/**
 * @author Philipp Hannemann & Christoph Lehnert
 */

package org.bonn.ooka.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.bonn.ooka.model.ComponentPointer;
import org.bonn.ooka.model.IComponentAssembler;

public class ComponentAssemblerUser {

	private long ID_COUNTER = 0;

	private boolean m_running = true;
	private IComponentAssembler m_asm = null;

	private Map<Long, ComponentPointer<?>> m_mapping = new HashMap<>();

	public ComponentAssemblerUser(IComponentAssembler cre) {
		this.m_asm = cre;
	}

	public boolean isRunning() {
		return this.m_running;
	}

	public void parse(String line) {
		if (line == null || line == "" || line.startsWith("#"))
			return;

		line = line.trim();

		if (testStatus(line.toLowerCase()))
			return;

		if (testStartStop(line.toLowerCase()))
			return;

		if (testDeploy(line))
			return;

		if (testErase(line))
			return;

		if (testExec(line))
			return;

		if (testKill(line))
			return;
		
		if (testChangeScope(line))
			return;
	}

	private boolean testStatus(String line) {
		if (line.startsWith("status")) {
			System.out.println(this.m_asm.status());
			return true;
		}
		return false;
	}

	private boolean testExec(String line) {
		if (line.startsWith("exec")) {
			String[] s = splitParameters(line);

			Long id = Long.parseLong(s[1].trim());

			Object[] obj = new Object[Math.max(s.length - 2, 0)];
			System.arraycopy(s, 2, obj, 0, s.length - 2);

			if (this.m_mapping.containsKey(id)) {
				this.m_asm.exec(this.m_mapping.get(id), obj);
			}

			return true;
		}
		return false;
	}
	
	private boolean testChangeScope(String line) {
		if (line.startsWith("changescope")) {
			String[] s = splitParameters(line);

			Long id = Long.parseLong(s[1].trim());
			String scope = s[2];
			
			if (this.m_mapping.containsKey(id)) {
				this.m_asm.changeScope(this.m_mapping.get(id), scope);
			}

			return true;
		}
		return false;
	}

	private boolean testKill(String line) {
		if (line.startsWith("kill")) {
			String[] s = splitParameters(line);

			if (s.length != 2) {
				System.err
						.println("Too many or too less Parameters (!= 2) - '\"' forgotten?");
				return true;
			}

			Long id = Long.parseLong(s[1].trim());

			if (this.m_mapping.containsKey(id)) {
				this.m_asm.kill(this.m_mapping.get(id));
			}

			return true;
		}
		return false;
	}

	private boolean testDeploy(String line) {
		if (line.startsWith("deploy")) {

			String[] s = splitParameters(line);

			if (s.length < 2 || s.length > 3) {
				System.err
						.println("Too many or too less Parameters (!= 3) - '\"' forgotten?");
				return true;
			}

			ComponentPointer<?> ptr = null;
			if (s.length == 2) {
				String xmlPath = s[1];

				ptr = this.m_asm.deploy(xmlPath);
			} else if (s.length == 3) {

				String jarPath = s[1];
				String className = s[2];

				ptr = this.m_asm.deploy(jarPath, className);
			}

			assert(ptr != null);
			
			Long id = ID_COUNTER++;

			this.m_mapping.put(id, ptr);

			return true;
		}
		return false;
	}

	private boolean testErase(String line) {
		if (line.startsWith("erase")) {
			String[] s = splitParameters(line);

			if (s.length != 2) {
				System.err
						.println("Too many or too less Parameters (!= 2) - '\"' forgotten?");
				return true;
			}

			Long id = Long.parseLong(s[1].trim());

			if (this.m_mapping.containsKey(id)) {
				this.m_asm.erase(this.m_mapping.get(id));
			}

			return true;
		}
		return false;
	}

	private boolean testStartStop(String line) {
		boolean postiveTested = false;

		if (line.startsWith("start")) {
			this.m_asm.start();
			this.m_running = true;
			postiveTested = true;
		} else if (line.startsWith("stop")) {
			this.m_asm.stop();
			this.m_running = false;
			postiveTested = true;
		}

		return postiveTested;
	}

	private static String[] splitParameters(String line) {
		Matcher mat = Pattern.compile("(\"(.*?)\"|([^ ]+)),?").matcher(line);
		List<String> result = new ArrayList<String>();
		while (mat.find()) {
			result.add(mat.group(2) == null ? mat.group(3) : mat.group(2));
		}
		String[] array = result.toArray(new String[result.size()]);

		return array;
	}
}
